home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Personal Computer World 2005 October
/
PCWOCT05.iso
/
Software
/
FromTheMag
/
XAMPP 1.4.14
/
xampp-win32-1.4.14-installer.exe
/
xampp
/
php
/
pear
/
FSM.php
< prev
next >
Wrap
PHP Script
|
2004-03-24
|
10KB
|
284 lines
<?php
/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */
/* +----------------------------------------------------------------------+
* | PHP Version 4 |
* +----------------------------------------------------------------------+
* | Copyright (c) 1997-2003 The PHP Group |
* +----------------------------------------------------------------------+
* | This source file is subject to version 2.02 of the PHP license, |
* | that is bundled with this package in the file LICENSE, and is |
* | available at through the world-wide-web at |
* | http://www.php.net/license/2_02.txt. |
* | If you did not receive a copy of the PHP license and are unable to |
* | obtain it through the world-wide-web, please send a note to |
* | license@php.net so we can mail you a copy immediately. |
* +----------------------------------------------------------------------+
* | Authors: Jon Parise <jon@php.net> |
* +----------------------------------------------------------------------+
*
* $Id: FSM.php,v 1.8 2003/10/03 07:52:11 jon Exp $
*/
/**
* This class implements a Finite State Machine (FSM).
*
* In addition to maintaining state, this FSM also maintains a user-defined
* payload, therefore effectively making the machine a Push-Down Automata
* (a finite state machine with memory).
*
* @author Jon Parise <jon@php.net>
* @version $Revision: 1.8 $
* @package FSM
*/
class FSM
{
/**
* Represents the initial state of the machine.
*
* @var string
* @see $_currentState
* @access private
*/
var $_initialState = '';
/**
* Contains the current state of the machine.
*
* @var string
* @see $_initialState
* @access private
*/
var $_currentState = '';
/**
* Contains the payload that will be passed to each action function.
*
* @var mixed
* @access private
*/
var $_payload = null;
/**
* Maps (inputSymbol, currentState) --> (action, nextState).
*
* @var array
* @see $_inputState, $_currentState
* @access private
*/
var $_transitions = array();
/**
* Maps (currentState) --> (action, nextState).
*
* @var array
* @see $_inputState, $_currentState
* @access private
*/
var $_transitionsAny = array();
/**
* Contains the default transition that is used if no more appropriate
* transition has been defined.
*
* @var array
* @access private
*/
var $_defaultTransition = null;
/**
* This method constructs a new Finite State Machine (FSM) object. In
* addition to defining the machine's initial state, a "payload" may also
* be specified. The payload represents a variable that will be passed
* along to each of the action functions. If the FSM is being used for
* parsing, the payload is often a array that is used as a stack.
*
* @param string $initialState The initial state of the FSM.
* @param mixed $payload A payload that will be passed to each
* action function.
*/
function FSM($initialState, &$payload)
{
$this->_initialState = $initialState;
$this->_currentState = $initialState;
$this->_payload = &$payload;
}
/**
* This method resets the FSM by setting the current state back to the
* initial state (set by the constructor). The current input symbol is
* also reset to NULL.
*/
function reset()
{
$this->_currentState = $this->_initialState;
$this->_inputSymbol = null;
}
/**
* This method adds a new transition that associates:
*
* (symbol, currentState) --> (nextState, action)
*
* The action may be set to NULL, in which case the processing routine
* will ignore the action and just set the next state.
*
* @param string $symbol The input symbol.
* @param string $state This transition's starting state.
* @param string $nextState This transition's ending state.
* @param string $action The name of the function to invoke
* when this transition occurs.
*
* @see addTransitions()
*/
function addTransition($symbol, $state, $nextState, $action = null)
{
$this->_transitions["$symbol,$state"] = array($nextState, $action);
}
/**
* This method adds the same transition for multiple different symbols.
*
* @param array $symbols A list of input symbols.
* @param string $state This transition's starting state.
* @param string $nextState This transition's ending state.
* @param string $action The name of the function to invoke
* when this transition occurs.
*
* @see addTransition()
*/
function addTransitions($symbols, $state, $nextState, $action = null)
{
foreach ($symbols as $symbol) {
$this->addTransition($symbol, $state, $nextState, $action);
}
}
/**
* This method adds a new transition that associates:
*
* (currentState) --> (nextState, action)
*
* The processing routine checks these associations if it cannot first
* find a match for (symbol, currentState).
*
* @param string $state This transition's starting state.
* @param string $nextState This transition's ending state.
* @param string $action The name of the function to invoke
* when this transition occurs.
*
* @see addTransition()
*/
function addTransitionAny($state, $nextState, $action = null)
{
$this->_transitionsAny[$state] = array($nextState, $action);
}
/**
* This method sets the default transition. This defines an action and
* next state that will be used if the processing routine cannot find a
* suitable match in either transition list. This is useful for catching
* errors caused by undefined states.
*
* The default transition can be removed by setting $nextState to NULL.
*
* @param string $nextState The transition's ending state.
* @param string $action The name of the function to invoke
* when this transition occurs.
*/
function setDefaultTransition($nextState, $action)
{
if (empty($nextState)) {
$this->_defaultTransition = null;
return;
}
$this->_defaultTransition = array($nextState, $action);
}
/**
* This method returns (nextState, action) given an input symbol and
* state. The FSM is not modified in any way. This method is rarely
* called directly (generally only for informational purposes).
*
* If the transition cannot be found in either of the transitions lists,
* the default transition will be returned. Note that it is possible for
* the default transition to be set to NULL.
*
* @param string $symbol The input symbol.
*
* @return mixed Array representing (nextState, action), or NULL if the
* transition could not be found and not default
* transition has been defined.
*/
function getTransition($symbol)
{
$state = $this->_currentState;
if (array_key_exists("$symbol,$state", $this->_transitions)) {
return $this->_transitions["$symbol,$state"];
} elseif (array_key_exists($state, $this->_transitionsAny)) {
return $this->_transitionsAny[$state];
} else {
return $this->_defaultTransition;
}
}
/**
* This method is the main processing routine. It causes the FSM to
* change states and execute actions.
*
* The transition is determined by calling getTransition() with the
* provided symbol and the current state. If no valid transition is found,
* process() returns immediately.
*
* The action callback may return the name of a new state. If one is
* returned, the current state will be updated to the new value.
*
* If no action is defined for the transition, only the state will be
* changed.
*
* @param string $symbol The input symbol.
*
* @see processList()
*/
function process($symbol)
{
$transition = $this->getTransition($symbol);
/* If a valid array wasn't returned, return immediately. */
if (!is_array($transition) || (count($transition) != 2)) {
return;
}
/* Update the current state to this transition's exit state. */
$this->_currentState = $transition[0];
/* If an action for this transition has been specified, execute it. */
if (!empty($transition[1])) {
$state = call_user_func_array($transition[1],
array($symbol, &$this->_payload));
/* If a new state was returned, update the current state. */
if (!empty($state) && is_string($state)) {
$this->_currentState = $state;
}
}
}
/**
* This method processes a list of symbols. Each symbol in the list is
* sent to process().
*
* @param array $symbols List of input symbols to process.
*/
function processList($symbols)
{
foreach ($symbols as $symbol) {
$this->process($symbol);
}
}
}
?>